﻿using System;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using System.Diagnostics;
using wdwp.Desktop.widgetLib.CommonTypes;
using wdwp.Desktop.widgetLib.Utils;

namespace wdwp.Desktop.Launcher
{

    /// <summary>
    /// 위젯 소스들을 탐색하고 관리 
    /// </summary>
    internal class WidgetSrcManager
    {

        /// <summary>
        /// 스캔된 위젯 정보들을 저장하고 있는 리스트
        /// </summary>
        ArrayList m_arWidgetSrcInfos;
        /// <summary>
        /// 위젯 소스들이 저장된 루트 경로
        /// </summary>
        string    m_strWidgetSrcRoot;

        public delegate void srcManagerEventHandler(object sender, WidgetEventArgs args);
        /// <summary>
        /// 소스 로딩이 완료되었을때 발생하는 이벤트
        /// </summary>
        public static event srcManagerEventHandler SrcLoadCompleted;
        /// <summary>
        /// 소스 관리중 발생하는 이벤트
        /// </summary>
        public static event srcManagerEventHandler Message;


        /// <summary>
        /// 위젯을 로드하는 매니저를 실행시킵니다. 
        /// </summary>
        /// <param name="strWdgtSrcRoot">위젯 소스폴더들의 루트 디렉토리</param>
        public WidgetSrcManager(string strWdgtSrcRoot)
        {
            m_arWidgetSrcInfos = new ArrayList();

            m_strWidgetSrcRoot = strWdgtSrcRoot;
            
            //doSearch(strWdgtSrcRoot);            
        }

        /// <summary>
        /// 위젯정보를 검색하고 로드합니다. 
        /// </summary>
        public void Start()
        {
            try
            {
                DoSearch(m_strWidgetSrcRoot);
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }


        /// <summary>
        /// 위젯정보를 재 검색하고 로드합니다. 
        /// </summary>
        public void Refresh()
        {
            try
            {
                m_arWidgetSrcInfos.Clear();

                Start();
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }


        /// <summary>
        /// 주어진 폴더의 하위 폴더를 뒤지면서 소스가 존재하는지, 있다면 어느 타입인지 알아냅니다.
        /// </summary>
        /// <param name="strWdgtSrcRoot">위젯 소스폴더들의 루트 디렉토리</param>
        private void DoSearch(string strWdgtSrcRoot)
        {
            try
            {
                DirectoryInfo dirSrcRoot = new DirectoryInfo(strWdgtSrcRoot);

                DirectoryInfo[] srcDirs = dirSrcRoot.GetDirectories();
                if (srcDirs.Length == 0) throw new Exception("Cannot find any widget sub dirs");

                foreach (DirectoryInfo aSrcDir in srcDirs)
                {
                    string HTMLfilePath = "";
                    string Type = VerifySrc(aSrcDir, ref HTMLfilePath);


                    if (Type == sWidgetTypes.FLASH_WIDGET)
                    {
                        ParseFlashHTML(HTMLfilePath);
                    }
                    else if (Type == sWidgetTypes.AG_WIDGET)
                    {
                        ParseAgHTML(HTMLfilePath);
                    }
                    else
                    {
                        Message(this, new WidgetEventArgs(sWidgetTypes.INVALID_WIDGET, "경로"
                            + aSrcDir.FullName + "엔 위젯 소스가 없거나 잘못된 형식의 위젯소스가 있으므로 로딩할수 없습니다."));
                    }

                }

                //로딩이 완료되면 완료되었다는 이벤트를 뿌림 
                SrcLoadCompleted(this, new WidgetEventArgs("widgetSrcManager", this.m_arWidgetSrcInfos));
            }
            catch (DirectoryNotFoundException exc)
            {
                throw new Exception("위젯 폴더 또는 위젯 소스가 담긴 폴더를 찾을수가 없습니다.\n 위젯 폴더의 이름이 \"widgets\"이라고 되어 있습니까?", exc);
            }
            catch (Exception exc)
            {
#if DEBUG
                Debug.WriteLine(exc.ToString()); 
#endif
                throw exc;
            }
        }

        /// <summary>
        /// 위젯 소스의 타입을 분별함
        /// </summary>
        /// <param name="srcDir">소스파일들을 담고있는 폴더</param>
        /// <param name="strHTMLPath">소스파일의 HTML 경로</param>
        /// <returns>정의된 소스의 타입</returns>
        private string VerifySrc(DirectoryInfo srcDir, ref string strHTMLPath)
        {          

            //flash - project이름.swf & project이름.html
            //silverlight - default.html & silverlight.js

            FileInfo[] JSfiles = srcDir.GetFiles("*.js");
            FileInfo[] SWFfiles = srcDir.GetFiles("*.swf");

            try
            {                   
                //실버라이트 위젯인가?
                foreach (FileInfo aFile in JSfiles)
                {
                    if (aFile.Name == "Silverlight.js")  //silverlight.js 파일이 있으면 실버라이트로 간주
                    {
                        strHTMLPath = aFile.DirectoryName + "\\default.html";
                        return sWidgetTypes.AG_WIDGET;
                    }
                }

                //플래쉬 위젯인가?

                JSfiles = srcDir.GetFiles("AC_RunActiveContent.js");

                foreach (FileInfo aFile in SWFfiles)  //SWF파일과 동일한 이름의 HTML이 있거나 AC_RunActiveContent 있으면 플래쉬로 간주
                {
                    FileInfo[] htmlFile = srcDir.GetFiles(aFile.Name.Substring(0, aFile.Name.Length - 4) + ".html");

                    if(htmlFile.Length > 0 && JSfiles.Length > 0)
                    {
                        strHTMLPath = htmlFile[0].FullName; //aFile.DirectoryName + "\\" + aFile.Name + ".html";
                        return sWidgetTypes.FLASH_WIDGET;
                    }
                }


                //모르는 타입인가?
                return sWidgetTypes.INVALID_WIDGET;                

            }
            catch (Exception exc)
            {                
                throw exc;
            }
        }

               

        /// <summary>
        /// Flash HTML 소스를 분석하여 필요한 정보를 추출합니다. 
        /// </summary>
        /// <param name="strSrcPath">Flash를 임베딩하고 있는 HTML소스</param>
        private void ParseFlashHTML(string strSrcPath)
        {
            try
            {
                StreamReader sr = File.OpenText(strSrcPath);
                string HTMLText = sr.ReadToEnd();
                StringParser parser = new StringParser(HTMLText);

                //HTML안에서 위젯의 이름을 얻어냄
                string Name = "";

                HTMLText = StringParser.removeComments(HTMLText);
                parser = new StringParser(HTMLText);

                parser.skipToEndOfNoCase("<title>");
                parser.extractTo("</title>", ref Name);


                //HTML안에서 위젯의 크기를 얻어냄 
                string height = "", width = "";

                HTMLText = StringParser.removeComments(HTMLText);
                parser = new StringParser(HTMLText);

                parser.skipToEndOf("'width', '");
                parser.extractTo("',", ref width);

                parser.skipToEndOf("'height', '");
                parser.extractTo("',", ref height);

                width = width.Trim('\'');
                height = height.Trim('\'');

                Console.WriteLine("Name: {0}, width: {1}, height: {2}\n", Name, width, height);

                //생성한 구조체로 위젯을 리스트에 등록 
                RegWidget(new sWidgetInfo(Name, int.Parse(height), int.Parse(width), sWidgetTypes.FLASH_WIDGET, strSrcPath));
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.ToString(), this.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
              
        }

        /// <summary>
        /// 실버라이트 HTML 소스를 분석하여 필요한 정보를 추출합니다. 
        /// </summary>
        /// <param name="strSrcPath">실버라이트를 임베딩하고 있는 HTML소스</param>
        private void ParseAgHTML(string strSrcPath)
        {         
            try
            {
                StreamReader sr = File.OpenText(strSrcPath);
                string HTMLText = sr.ReadToEnd();
                StringParser parser = new StringParser(HTMLText);

                //HTML안에서 위젯의 이름을 얻어냄
                string Name = "";

                HTMLText = StringParser.removeComments(HTMLText);
                parser = new StringParser(HTMLText);

                parser.skipToEndOfNoCase("<title>");
                parser.extractTo("</title>", ref Name);


                //HTML안에서 위젯의 크기를 얻어냄 
                string height = "", width = "";

                HTMLText = StringParser.removeHtml(HTMLText);
                parser = new StringParser(HTMLText);

                //for silverlight 1.0
                if (parser.skipToStartOf(".silverlightHost") || parser.skipToStartOf("#silverlightControlHost"))
                {
                    parser.skipToEndOf("width:");
                    parser.extractTo("px;", ref width);
                    parser.resetPosition();

                    parser.skipToEndOf("height:");
                    parser.extractTo("px;", ref height);
                }
                else //만일 HTML안에 스타일 설정이 없다면 JS 파일을 뒤짐 
                {                    
                    //for silverlight 0.98
                    
                    /*
                    //디렉토리 뒤져서 다음의 조건대로 한다.
                    //js 파일중에 _html.js이 있다. -> 처리
                    int index = strSrcPath.LastIndexOf('\\');
                    string dir = strSrcPath.Substring(0, index + 1);

                    DirectoryInfo srcdir = new DirectoryInfo(dir);                    
                    FileInfo[] files = srcdir.GetFiles("*_html.js");

                    if (files.Length > 0)
                    {
                        strSrcPath
                    }
                    */



                    //js 파일중에 .html.js이 있다. -> 처리

                    sr = File.OpenText(strSrcPath + ".js");
                    HTMLText = sr.ReadToEnd();
                    HTMLText = StringParser.removeEnclosingQuotes(HTMLText);
                    parser = new StringParser(HTMLText);

                    parser.skipToEndOf("properties:");

                    parser.skipToEndOf("width: ");
                    parser.extractTo(",", ref width);
                    parser.resetPosition();

                    width = width.Trim('\"');

                    parser.skipToEndOf("height: ");
                    parser.extractTo(",", ref height);

                    height = height.Trim('\"');
                }

                Console.WriteLine("Name: {0}, width: {1}, height: {2}\n", Name, width, height);

                //생성한 구조체로 위젯을 리스트에 등록 
                RegWidget(new sWidgetInfo(Name, int.Parse(height), int.Parse(width), sWidgetTypes.AG_WIDGET, strSrcPath));
             
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.ToString(), this.ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error);
                //Message(this, new WidgetEventArgs(
            }            
                      
        }


        /// <summary>
        /// 구조체의 정보를 가지고 위젯을 등록시킵니다.
        /// </summary>
        /// <param name="SrcInfo"></param>
        private bool RegWidget(sWidgetInfo SrcInfo)
        {
            //동일한 이름의 위젯이 있는가 체크 
            foreach (sWidgetInfo aInfo in m_arWidgetSrcInfos)
            {
                if (aInfo.Name == SrcInfo.Name)
                {
                    Debug.WriteLine("Same widget exists" + aInfo.Name);
                    return false;
                }
            }

            m_arWidgetSrcInfos.Add(SrcInfo);
            return true;
        }


        /// <summary>
        /// 위젯의 이름을 가지고 등록된 위젯을 삭제합니다. 
        /// </summary>
        /// <param name="WidgetName">삭제할 위젯의 이름</param>
        public bool UnRegWidget(string WidgetName)
        {
            //ArrayList를 탐색하면서 동일한 이름의 위젯을 찾음 
            //발견하면 인덱스를 가지고 이를 삭제 

            foreach (sWidgetInfo aInfo in m_arWidgetSrcInfos)
            {
                if (aInfo.Name == WidgetName)
                {
                    m_arWidgetSrcInfos.Remove(aInfo);
                    return true;
                }
            }

            Debug.WriteLine("Cannot find such Name in widgetInfo");
            return false;
        }


        /// <summary>
        /// 위젯들의 메타정보를 가지고 있는 리스트를 얻어옵니다. 
        /// </summary>
        public ArrayList WidgetSrcList
        {
            get
            {
                return m_arWidgetSrcInfos;
            }
        }
 
    }

}